<template>
  <div class="page-layout ver-layout-center" :class="themeObj.titleClass" :style="themeObj.pageStyle">
    <div class="title-layout hor-layout-side-center">
      <div class="title-left-layout ver-layout-center-all" @click="openDrawer">
        <img class="title-left-icon" src="https://noss.douguguo.com/static/image/menu.png"/>
      </div>
      <div class="title-div">New chat</div>
      <div class="title-right-div" @click="toPage(minePage)">个人中心</div>
    </div>
    <div v-show="showChatContent" ref="chatContentRef" scroll-y scroll-with-animation
         class="chat_content-layout ver-layout scroll-Y">
      <div v-for="(item,index) in messageArr" :key="index" :id="'chatItemView'+index" class="chat-item">
        <!--   创建时间     -->
        <div v-if="item.create_time && item.role==='user'" class="message-time">{{ item.create_time }}</div>
        <!--   ai内容     -->
        <div v-if="item.role==='assistant'" class="hor-layout assistant-content">
          <img class="chat-user-icon" src="https://noss.douguguo.com/static/image/ai.png"/>
          <div class="chat-content"
               :class="[{'waiting':(index===messageArr.length-1)&&item.flag==='last'},themeObj.bottomInputClass]">
            <div v-if="item.flag==='last'" class="chat-content-text" v-html="compiledMarkdown(chatContent)"></div>
            <div v-else class="chat-content-text" v-html="compiledMarkdown(item.content)"></div>
          </div>
        </div>
        <!--   用户内容     -->
        <div v-else class="hor-layout use-content">
          <div class="chat-content" :class="themeObj.bottomInputClass">{{ item.content }}</div>
          <img class="chat-user-icon" src="https://noss.douguguo.com/static/image/user.png"/>
        </div>
      </div>
    </div>
    <div v-show="!showChatContent" :class="{'bounceInUpSoon':!showChatContent}" class="demo-content-layout">
      <div class="main-title" :class="themeObj.titleClass">
        Chat Ai
      </div>
      <div class="ver-layout" v-for="(item,index) in textList" :key="index">
        <div class="hor-layout-center-all" style="margin-bottom: 15px">
          <img class="demo-icon" :src="themeObj[item.textIcon]"/>
          <div :class="themeObj.titleClass">{{ item.title }}</div>
        </div>
        <div v-for="(text,index) in item.list" :key="index" :class="themeObj.textItemClass"
             class="hor-layout-center-all text-item">
          <div @click="textItemClick(item,text)">{{ text }}</div>
          <img v-if="item.title=='使用示例'" class="text-icon"
               src="https://noss.douguguo.com/static/image/more.png"/>
        </div>
      </div>
    </div>
    <div class="bottom-chat-layout hor-layout-center-all" :class="themeObj.bottomClass">
      <input v-model="inputValue" :disabled="sendDisabled" type="textarea" class="chat-input"
             :class="themeObj.bottomInputClass" @keydown.enter="sendMessage">
      <div v-show="sendDisabled" class="dot-flashing"></div>
      <img v-show="!sendDisabled" class="bottom-input-icon" :src="themeObj.bottomInputIconSrc"
           @click="sendMessage"/>
    </div>
    <!--  弹窗  -->
    <el-dialog ref="drawer" width="300" :visible="showDrawer" center fullscreen>
      <div class="ver-layout drawer-layout">
        <div class="new-chat-layout hor-layout-side-center">
          <div class="new-chat-title">新的对话</div>
          <img class="add-icon" src="https://noss.douguguo.com/static/image/add.png"/>
        </div>
        <div style="height: 50vh;overflow-y: scroll;">
          <div class="chat-questions single-line-text" v-for="(item,index) in myQuestions" :key="index">
            <div>{{ item.content }}</div>
          </div>
        </div>
        <div class="ver-layout drawer-setting-layout">
          <div class="hor-layout-center drawer-setting-item" @click="settingItemClick('clear')">
            <img class="setting-icon" src="https://noss.douguguo.com/static/image/del.png"/>
            <div class="setting-text">清除对话</div>
          </div>
          <div class="hor-layout-center drawer-setting-item" @click="settingItemClick('question')">
            <img class="setting-icon" src="https://noss.douguguo.com/static/image/help.png"/>
            <div class="setting-text">常见问题</div>
          </div>
          <div class="hor-layout-center drawer-setting-item" @click="settingItemClick('mode')">
            <div v-if="appTheme==='white'">
              <img class="setting-icon" src="https://noss.douguguo.com/static/image/month.png"/>
              <div class="setting-text">夜间模式</div>
            </div>
            <div v-else>
              <img class="setting-icon" src="https://noss.douguguo.com/static/image/sun.png"/>
              <div class="setting-text">日间模式</div>
            </div>
          </div>
        </div>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import {chatApi} from "../../api/chat"
import {textList, themeData} from "./themeData"
import MarkdownIt from "markdown-it";
import Deflist from "markdown-it-deflist";
import Anchor from "markdown-it-anchor";
import tableOfContents from "markdown-it-table-of-contents";
import markdownItMultimdTable from "markdown-it-multimd-table";

export default {
  name: "difyTest",
  data() {
    return {
      chatContent: "",
      themeData,
      textList,
      inputValue: '',
      appTheme: '',
      sendDisabled: false,
      showChatContent: false,
      chatList: [],
      messageList: [
        // {role: 'user', content: '用js绘制一个动态图形'},
        // {
        //   role: 'assistant',
        //   content: "要绘制一个动态图形，常用的工具是Canvas和SVG，这里我们使用Canvas来实现。\n\n代码实现如下：\n\nHTML部分：\n\n```html\n<canvas id=\"canvas\"></canvas>\n```\n\nJS部分：\n\n```javascript\nconst canvas = document.getElementById(\"canvas\"); // 获取canvas元素\nconst ctx = canvas.getContext(\"2d\"); // 获取绘图上下文\n\n// 初始化圆形的位置和大小参数\nlet x = 50;\nlet y = 50;\nlet r = 20;\n\n// 设置每一帧动画的更新函数\nfunction update() {\n  ctx.clearRect(0, 0, canvas.width, canvas.height); // 清空画布\n\n  // 绘制圆形\n  ctx.beginPath();\n  ctx.arc(x, y, r, 0, Math.PI * 2);\n  ctx.fillStyle = \"red\";\n  ctx.fill();\n\n  // 更新圆形的位置和大小\n  x += 2;\n  y += 2;\n  r += 1;\n\n  // 在下一帧执行更新函数\n  requestAnimationFrame(update);\n}\n\n// 开始动画\nrequestAnimationFrame(update);\n```\n\n这个例子中，我们使用Canvas的`getContext`方法获取了绘图上下文对象，在动画的每一帧中，我们使用`clearRect`方法清空画布，并绘制一个圆形。每一帧结束后，我们调用`requestAnimationFrame`方法，在下一帧执行更新函数，实现了一个简单的动画效果。"
        // },
        // {role: 'user', content: '用js绘制一个动态图形'},
      ],
      targetView: '',
      chatScrollTop: 10000,
      ipInfo: '',
      systemInfo: {},
      minePage: "",
      md: "",
      showDrawer: false
    }
  },
  computed: {
    themeObj() {
      let theme = this.appTheme
      let data = this.themeData[theme]
      return data
    },
    messageArr() {
      let list = []
      this.messageList.forEach(item => {
        let content = item.content && item.content.replace(/\n\n/g, "\n")
        // if (item.role == 'assistant') content = this.convertStrList(content)
        list.push({...item, content})
      })
      return list
    },
    myQuestions() {
      return this.messageList.filter(item => item.role === 'user')
    }
  },
  watch: {
    nowPhoneHeight: {
      handler(newVal) {
      }
    },
    showChatContent: {
      handler(newVal) {
      },
      immediate: true
    }
  },
  created() {
    this.appTheme = 'dark'
    this.initListener()
    this.initMarkdown()
  },
  methods: {
    initMarkdown() {
      // 所有的选项列表（默认情况下）
      const md = new MarkdownIt({
        html: false, // 在源码中启用 HTML 标签
        xhtmlOut: false, // 使用 '/' 来闭合单标签。这个选项只对完全的 CommonMark 模式兼容。
        breaks: false, // 转换段落里的 '\n' 到 <br>。
        langPrefix: 'language-', // 给围栏代码块的 CSS 语言前缀。对于额外的高亮代码非常有用。
        linkify: false, // 将类似 URL 的文本自动转换为链接。
        typographer: false, // 启用一些语言中立的替换 + 引号美化
        quotes: '“”‘’', // 双 + 单引号替换对，当 typographer 启用时。或智能引号等，可以是String或 Array。
        highlight: function (/*str, lang*/) {
          return '';
        }, // 高亮函数，会返回转义的HTML。
      });
      // 插件使用，根据需要选用
      md.use(Deflist);
      md.use(Anchor.default);
      md.use(tableOfContents);
      md.use(markdownItMultimdTable, {
        multiline: false,
        rowspan: false,
        headerless: false,
        multibody: true,
        autolabel: true,
      });
      this.md = md
    },
    compiledMarkdown(text) {
      return text && this.md && this.md.render(text); // 渲染Markdown内容
    },
    toPage(url) {
      // this.$tools.pageGo(url)
    },
    initListener() {
      // uni.getSystemInfo({
      //   success: res => {
      //     this.systemInfo = res
      //     this.getMessageHistory()
      //   }
      // });
      this.getMessageHistory()
      this.$nextTick(() => {
        this.defaultPhoneHeight = window.innerHeight
        window.onresize = () => {
          console.log("window.onresize")
          this.nowPhoneHeight = window.innerHeight
          this.scrollContent()
        }
      })
    },
    convertStrList(str) {
      let str_list = str.split("```")
      str_list = str_list.map((item, index) => {
        if ((index + 1) % 2 != 0) return {type: 'text', data: item}
        else return {type: 'code', data: item}
      })
      return str_list
    },
    textItemClick(item, text) {
      if (item.title !== '使用示例') return
      this.inputValue = text.replace(/“/g, "")
    },
    getMessageHistory() {
      let {deviceId} = this.systemInfo
      chatApi.getMessageHistory().then(res => {
        if (res.data && res.data.length) this.showChatContent = true
        let historyList = []
        res.data.forEach(item => {
          historyList.push({role: "user", content: item.query})
          historyList.push({role: "assistant", content: item.answer})
        })
        this.updateChatContent(historyList)
      })
    },
    sendMessage() {
      let mInputValue = this.inputValue
      if (!mInputValue) {
        this.$tools.showToast('请输入问题！')
        return
      }
      if (this.sendDisabled) return
      this.sendDisabled = true
      this.updateChatLayout({role: 'user', content: mInputValue})
      this.updateChatLayout({role: 'assistant', content: "", flag: "last"})
      this.inputValue = ''
      this.showChatContent = true
      this.chatContent = ""
      chatApi.sendMessage(mInputValue, {}, (data) => {
        console.log("sendMessage==", data)
        this.chatContent += data.answer
        this.$nextTick(() => {
          const container = this.$refs.chatContentRef;
          container.scrollTop = container.scrollHeight;
        })
        if (data.event === "message_end") {
          this.updateLastChatContent(this.chatContent)
          this.sendDisabled = false
        }
      })
    },
    updateChatContent(list) {
      this.messageList = [...this.messageList, ...list]
      this.$nextTick(() => {
        const container = this.$refs.chatContentRef;
        container.scrollTop = container.scrollHeight;
      })
    },
    updateChatLayout(message, removeLast = false) {
      if (message.flag !== 'last') this.chatList.push(message)
      if (removeLast) this.messageList.pop()
      this.messageList.push(message)
      this.$nextTick(() => {
        const container = this.$refs.chatContentRef;
        container.scrollTop = container.scrollHeight;
      })
    },
    updateLastChatContent(content) {
      this.messageList = this.messageList.map((item, index) => {
        if (index === this.messageList.length - 1) item.content = content, item.flag = ""
        return item
      })
    },
    scrollContent() {
      setTimeout(() => {
        const container = this.$refs.chatContentRef;
        container.scrollTop = container.scrollHeight;
      })
    },
    openDrawer() {
      this.showDrawer = true
      // this.$refs.drawer.open()
    },
    closeDrawer() {
      this.showDrawer = false
      this.$refs.drawer.close()
    },
    settingItemClick(type) {
      if (type === 'mode') {
        // let theme = uni.getStorageSync("theme")
        // uni.setStorageSync('theme', theme == 'white' ? 'dark' : 'white')
        // this.appTheme = uni.getStorageSync("theme")
        this.$refs.drawer.close()
      }
      if (type == 'question') {
        this.showChatContent = false
        this.$refs.drawer.close()
      }
      if (type == 'clear') {
        // uni.showModal({
        //   content: "确定清除所有数据？",
        // }).then(res => {
        //   this.$refs.drawer.close()
        //   if (!res[1].confirm) return
        //   this.messageList.splice(0, this.messageList.length)
        //   this.$tools.showToast("清除成功！")
        // })
      }
    }
  }
}
</script>

<style scoped lang="less">
.page-layout {
  width: 100%;
  min-height: calc(100vh - var(--top-window-height))
}

.title-layout {
  position: fixed;
  width: 100%;
  height: 44px;
  background: #000;
  z-index: 100;
}

.title-left-layout {
  z-index: 100;
  width: 50px;
  height: 100%;
}

.title-left-icon {
  width: 16px;
  height: 11px;
}

.title-div {
  position: absolute;
  width: 100%;
  text-align: center;
  font-size: 18px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #fff;
}

.title-right-div {
  z-index: 100;
  font-size: 15px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #fff;
  padding-right: 15px;
}

.demo-content-layout {
  margin-top: calc(44px + 10px);
  margin-bottom: 150px;
}

.main-title {
  font-size: 40px;
  font-family: PingFang;
  font-weight: 700;
  text-align: center;
  margin: 15px 0;
}

.demo-icon {
  width: 22px;
  height: 22px;
}

.text-item {
  width: 345px;
  background: #f5f5f5;
  border-radius: 2px;
  padding: 15px 0;
  margin: 0 auto 10px;
  font-size: 15px;
}

.darkinput {
  background: #545454 !important;
  border: none !important;
  box-shadow: none !important;
  color: #fff !important;
}

.nightbot {
  background: #262626 !important;
  border: none !important;
}

.nightinput {
  background: #545454 !important;
  border: none !important;
  box-shadow: none !important;
  color: #fff !important;
}

.text-icon {
  width: 14px;
  height: 5px;
  margin-left: 10px;
}

.bottom-chat-layout {
  position: fixed;
  bottom: 0px;
  width: 100%;
  padding: 25px 0;
  background: #f9f9f9;
  border: 0.5px solid #d2d2d2;
}

.chat-input {
  width: calc(100% - 50px);
  background: #fff;
  border: 0.5px solid #cacaca;
  box-shadow: 0 1px 8px 0 hsla(0, 0%, 89%, .39);
  border-radius: 5px;
  font-size: 15px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #1a1818;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  padding: 15px;
}

.bottom-input-icon {
  position: absolute;
  right: 20px;
  width: 28px;
  height: 23px;
}

.bottom-input-icon:hover {
  opacity: 0.6;
}

/deep/ .el-dialog.is-fullscreen {
  background: #000;
}

.drawer-layout {
  width: 100%;
  height: 100%;
  background: #000;
  color: white;
}

.new-chat-layout {
  padding: 22px 17px 17px 12px;
  border-bottom: solid 0.5px #686868;
}

.new-chat-title {
  font-size: 20px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #fffefe;
}

.add-icon {
  width: 14px;
  height: 14px;
}

.chat-questions {
  margin-top: 15px;
  margin-left: 20px;
  margin-right: 10px;
  padding-bottom: 5px;
  font-size: 15px;
  border-bottom: 1px solid #e1e1e1;
}

.drawer-setting-layout {
  padding: 0 10px;
  border-top: solid 0.5px #686868;
}

.drawer-setting-item {
  width: 278px;
  padding: 15px 0 5px 12px;
  display: flex;
  align-items: center;
}

.setting-icon {
  width: 15px;
  height: 15px;
}

.setting-text {
  font-size: 16px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #fff;
  margin-left: 12px;
}

.content-layout {
  width: 100%;
}

.chat_content-layout {
  margin-top: calc(44px + 5px);
  height: calc(100vh - 44px - 100px);
  background: rgb(60, 60, 60);
  overflow-y: scroll;
}

.chat-item {
  margin-top: 10px;
  margin-bottom: 5px;
}

.chat-user-icon {
  flex-shrink: 0;
  width: 25px;
  height: 25px;
  border-radius: 50%;
  margin: 0 5px;
}

.message-time {
  background: #7b7878;
  color: white;
  width: fit-content;
  margin: 10px auto;
  font-size: 13px;
  padding: 3px 10px;
  border-radius: 4px;
}

.assistant-content {
  justify-content: flex-start;
}

.use-content {
  justify-content: flex-end;
}

.chat-content {
  white-space: pre-line;
  max-width: 285px;
  background: #f5f5f5;
  border: 0.5px solid #dbdbdb;
  border-radius: 2px;
  padding: 12px;
  font-size: 10px;
  font-family: PingFang SC;
  font-weight: 500;
  color: #3c3c3c;
  line-height: 1.5;
  word-wrap: break-word;
  -webkit-user-select: text;
  -ms-user-select: text;
  user-select: text; /* Standard syntax */
  //复制逻辑
  -webkit-user-select: auto;
  -moz-user-select: auto;
  user-select: auto;
}

.chat-code {
  background-color: #272822;
  color: #f8f8f2;
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  border-radius: 3px;
}

.chat-content.waiting::after {
  -webkit-animation: blink 1s steps(5, start) infinite;
  animation: blink 1s steps(5, start) infinite;
  content: "▋";
  margin-left: 0.25rem;
  vertical-align: baseline;
}

@-webkit-keyframes blink {
  to {
    visibility: hidden
  }
}

@keyframes blink {
  to {
    visibility: hidden
  }
}

/**
 * ==============================================
 * Dot Flashing
 * ==============================================
 */
.dot-flashing {
  //position: relative;
  position: absolute;
  right: 37px;
  width: 4px;
  height: 4px;
  border-radius: 2px;
  background-color: #333333;
  color: #333333;
  animation: dotFlashing 1s infinite linear alternate;
  animation-delay: .5s;
}

.dot-flashing::before, .dot-flashing::after {
  content: '';
  display: inline-block;
  position: absolute;
  top: 0;
}

.dot-flashing::before {
  left: -8px;
  width: 4px;
  height: 4px;
  border-radius: 2px;
  background-color: #333333;
  color: #333333;
  animation: dotFlashing 1s infinite alternate;
  animation-delay: 0s;
}

.dot-flashing::after {
  left: 8px;
  width: 4px;
  height: 4px;
  border-radius: 2px;
  background-color: #333333;
  color: #333333;
  animation: dotFlashing 1s infinite alternate;
  animation-delay: 1s;
}

@keyframes dotFlashing {
  0% {
    background-color: #333333;
  }
  50%,
  100% {
    background-color: #fffefe;
  }
}

@keyframes bounceInUp {

  from,
  60%,
  75%,
  90%,
  to {
    animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
  }

  from {
    opacity: 0;
    transform: translate3d(0, 100vh, 0);
  }

  60% {
    opacity: 1;
    transform: translate3d(0, -20px, 0);
  }

  75% {
    transform: translate3d(0, 10px, 0);
  }

  90% {
    transform: translate3d(0, -5px, 0);
  }

  to {
    transform: translate3d(0, 0, 0);
  }
}

.bounceInUp {
  animation-name: bounceInUp;
  animation-duration: 2s;
  animation-timing-function: linear;
}

.bounceInUpSoon {
  animation-name: bounceInUp;
  animation-duration: 1s;
  animation-timing-function: linear;
}
</style>
